Amazon PollyとPythonでお手軽スクレイピング&サーバーレスなポッドキャスト配信 #reinvent
はじめに
先日の re:Invent 2016 で Amazon Polly が発表されました。
高度な深層学習テクノロジーを使用した Amazon AI サービスの 1 つで、24 の言語と 47 の音声 で文章をリアルな音声に変換するサービスです。
Amazon Polly のユースケースとして、製品のトップページには「記事を音声に変換して MP3 でダウンロードする」という例が紹介されています。
Amazon Polly のウェビナーを視聴していると、このユースケースにあるような
- Python による RSS のクローリングとスクレイピング
- Amazon Polly の text-to-speech 変換
を駆使してサーバーレスにポッドキャスト配信サービスを構築するアーキテクチャーが紹介されていました。
本ブログでは Amazon Polly と AWS のサーバーレスサービスをうまく活用したこのアーキテクチャーをステップバイステップでウォークスルー形式で解説します。
ウォークスルーの流れ
- 音源を置く S3 の設定
- Lambda の設定
- Lambda 関数のテスト実行
- Lambda 関数のトリガー設定
- Lambda の動作確認
ステップ1:音源を置く S3 の設定
音源の設置先となる S3 バケットの設定を行います。
S3 バケットの作成
まず S3 バケットを新規に作成します。
静的ウェブホスティングの設定
次の作成したバケットのプロパティの Static Website Hosting で次のように設定します。
- Enable website hosting
- Index Document: podcast.xml
- Error Document: error.html
アクセス許可の設定
最後にすべてのユーザーがこの S3 バケット内のオブジェクトにアクセス出来るように、バケットポリシーを次のように設定します。
{ "Version":"2012-10-17", "Statement":[{ "Sid":"PublicReadForGetBucketObjects", "Effect":"Allow", "Principal": "*", "Action":["s3:GetObject"], "Resource":["arn:aws:s3:::BUCKET-NAME/*" ] } ] }
JSON ファイル内の BUCKET-NAME は実際に作成したバケット名に変更して下さい。
ステップ2:Lambda の設定
クローリング&スクレイピングする Lambda の設定をします。
Lambda 用 IAM ロールの作成
IAM の画面で新規ロール作成画面に遷移し
- Role Name : 必須
- Role Type : AWS Service Roles : AWS Lambda
- Attach Policy : スキップ
- プレビュー : 内容を確認後、作成
作成した IAM ロールを開き、 Inline Policies の Create Role Policy からインラインでパーミッションを設定します。
Lambda 関数の取得
Lambda 関数は GitHub にあがっているため、レポジトリ awslabs/amazon-polly-sample をクローンします。
$ git clone https://github.com/awslabs/amazon-polly-sample.git
Lambda 関数のアップロード
今回利用する Lambda 関数は クローンしたソースコードの以下のパスにあります。
mazon-polly-sample/dist/package.zip
AWS 管理画面にアップロードします。
Lambda 関数の新規作成画面に移動し次のように設定します。
Configure Triggers
あとで設定するため、「Next」
Configure function
- Name : 必須
- Decription : 任意
- Runtime : Python 2.7
- Lambda function code : GitHub から先程クローンした package.zip を指定
Lambda function handler and role
- Handler : lambda_function.lambda_handler
- Role : Create a custome role からロールの作成画面に遷移。ポリシーの編集画面に移動し、次のポリシーを設定
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "polly:SynthesizeSpeech", "s3:ListBucket", "s3:PutObject" ], "Resource": [ "*" ] } ] }
Lambda 関数は
- S3 からのキーの取得、S3 へのオブジェクトの PUT
- Polly の text-to-speech API 呼び出し
を行います。 このための最小限の権限を付与しています。
Advanced settings
クローリングを行うため、タイムアウト時間を伸ばします。
- Memory : 128 MB
- Timeout : 5 min
Review
入力した情報を確認後、問題がなければ Create function で作成します。
ステップ3 : Lambda 関数のテスト実行
作成した Lambda 関数の個別画面に遷移し、"Action" タブから "Configure Test Event" を選択します。
Inline test event の画面で、RSS フィードの URL と音源の保存先 S3 バケットを指定します。
{ "rss": "http://feeds.feedburner.com/AmazonWebServicesBlog", "bucket": "YOUR_BUCKET_NAME" }
今回は RSS フィードとして AWS Blog の RSS フィードを指定します。
YOUR_BUCKET_NAME
の箇所は作成した S3 バケット名に変更して下さい。
"Save and test" をクリックすると、テストイベントが保存され、Lambda 関数が実行されます。
初回実行時は、各フィードをテキストから音源に変換するため、時間がかかります。
実行結果(Execution result) が "succeeded" であれば成功です。 エラーが発生した場合は、エラーメッセージに従って調査して下さい。
ステップ4 : Lambda 関数のトリガー設定
CloudWatch Events を使って Lambda 関数を定期的に呼び出すように設定します。
CloudWatch Event Rule の作成
CloudWatch Events の Rules に移動し、"Create rule" からルール作成画面に移動します。
Event Selector
- Event source : Schedule
- 間隔 : Fixed rate of 1 Hours
Targets
- target type : Lambda function
- Function : 作成した Lambda 関数
- Configure version/alias : デフォルトのまま
- Configure input : 以下のJSON
{ "rss": "http://feeds.feedburner.com/AmazonWebServicesBlog", "bucket": "YOUR_BUCKET_NAME" }
クロールする RSS フィードと音源の保存先 S3 バケットを指定します。
YOUR_BUCKET_NAME
の箇所は作成した S3 バケット名に変更して下さい。
設定例
CloudWatch Event Rule の詳細設定
Rule の詳細を設定します。
- Name : 必須
- 概要 : 任意
- Stage : Enabled にチェック
ステップ5 : Lambda の動作確認
CloudWatch Event Scheduler を有効にしたあとは放置します。
翌日などに確認すると、 S3 のインデックスファイル(podcast.xml)が更新され、新しい記事が音源化されていることを確認できます。
$ curl --silent http://YOUR-BUCKET-NAME.s3-website.eu-central-1.amazonaws.com/podcast.xml <?xml version='1.0' encoding='UTF-8'?> <rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0"> <channel> <title>Audio podcast based on: AWS Security Blog</title> <link>https://aws.amazon.com/blogs/security/</link> <description>Just another AWS Brew Blogs site</description> <docs>http://www.rssboard.org/rss-specification</docs> <generator>python-feedgen</generator> <lastBuildDate>Thu, 22 Dec 2016 11:24:17 +0000</lastBuildDate> <item> <title>EU Compliance Update</title> <guid isPermaLink="false">728f967e2480fc19156cbd0790baef67d1e1850c_0</guid> <enclosure url="http://BUCKET.s3-website.eu-central-1.amazonaws.com/728f967e2480fc19156cbd0790baef67d1e1850c_0.mp3" length="0" type="audio/mpeg"/> <pubDate>Mon, 12 Dec 2016 14:50:32 +0000</pubDate> </item> <item> <title>EU Compliance Update</title> <guid isPermaLink="false">728f967e2480fc19156cbd0790baef67d1e1850c_1</guid> <enclosure url="http://BUCKET.s3-website.eu-central-1.amazonaws.com/728f967e2480fc19156cbd0790baef67d1e1850c_1.mp3" length="0" type="audio/mpeg"/> <pubDate>Mon, 12 Dec 2016 14:50:31 +0000</pubDate> </item> ...
S3バケットの中身
うまく動作していない時は、Lambda の実行ログを確認してください。
あとは作成した Podcast のフィードを登録するだけです。
ソースコードから Lambda パッケージの作成方法
GitHub からクローンした amazon-polly-sample
のトップディレクトリで
$ pip install -r requirements.txt -t . $ zip -r package.zip .
と実行すると、ソースコードから Lambda パッケージを作成できます。
Lambda 関数のカスタマイズポイント
以下で Lambda 関数のカスタマイズポイントを紹介します。
Polly のリージョン
現時点では Polly は一部のリージョンでのみ提供されています。 そのため、
from boto3 import Session ... session = Session(region_name="us-west-2") polly = session.client("polly")
というように Polly が提供されているリージョン向けにべた書きされています。
Lambda 関数と同じリージョンの Polly を利用する場合
from boto3 import client ... polly = client("polly")
というようにシンプルに書けます。
日本語の音声を利用
日本語を利用する場合は VoiceId を Mizuki に変更します。
response = polly.synthesize_speech( Text=entry['content'], OutputFormat="mp3", VoiceId="Mizuki")
最後に
今回は
- Python のクローリングとスクレイピング
- Amazon Polly の text to speech
- AWS のサーバーレス技術
を組み合わせてサーバーレスにポッドキャスト配信するアーキテクチャーを紹介しました。
Lambda 内のビジネスロジックをいじるだけで、いろいろ使いまわしができそうなサーバーレスアーキテクチャーとなっています。
簡単にいじれるため、ボット化や画像認識対応(Amazon Recognition)など、いろいろ遊んで見てはいかがでしょうか?